//
//  Game.cpp
//  Dungeons and Princesses
//
//  Created by phuong on 10/15/11.
//  Copyright (c) 2011 SD Networks. All rights reserved.
//
//  Updated many changes to include new methods for parsing commands from interface class
//  Modified by Christopher Bowlsby on 11/5/11

#include <iostream>

#include "Game.h"
#include "TextInterface.h"
#include "GuiInterface.h"
#include "Utility.h"
#include "Direction.h"
#include "Inventory.h"
#include "Key.h"
#include "Potion.h"
#include "EquipmentType.h"
#include "PlayerStats.h"
#include <string>
#include <sstream>

using namespace std;

Game::Game() {
    
    gameCastle = new Castle();
    
    currentRoom = gameCastle->getRoom("R0");
    
    Key *testKey = new Key("A Rusty Key", "aZ234d32");
    
    gameCastle->addByRoom(0, testKey);
    
    Potion *testPotion = new Potion();
    
    gameCastle->addByRoom(2, testPotion);
    
    EquipmentType *testEquipment = new EquipmentType();
    
    gameCastle->addByRoom(2, testEquipment);
    
    numberOfQuitRequests = 0;
    
}

void Game::run(int argc, char* argv[]) {
    
    myInterface = new GuiInterface(this, argc, argv);
    
    myInterface->setupPlayer();
    
    myInterface->loadInterface();
    // test the game update method, and passing info between the game interface and the delegate class (delegate == Game)
    myInterface->update();
    
    
    
}

Room * Game::getCurrentRoom() {
    
    return currentRoom;
}

Player * Game::getCurrentPlayer() {
    
    return currentPlayer;
}
void Game::setupPlayer(std::string playerName) {
    
    PlayerStats myStats = PlayerStats();
    
    currentPlayer = new Player(playerName, WARRIOR, myStats);
    
}
void Game::testDelegate(std::string myStringToTest) {
    
    std::cout << myStringToTest << std::endl;
    
}

void Game::executeCommand(std::string commandToParse) {
    
    // remove garbage from end of string
    commandToParse = Utility::removeGarbage(commandToParse);
    
    if (commandToParse.size() > 0) {
        commandToParse = Utility::lowerCase (commandToParse);
        cout << commandToParse << endl;
        
        vector<string> commands;
        
        Utility::getCommands(commandToParse, commands);
        Direction ddirection; 
        string id;
        if (commands[0] == "go" || commands[0] == "move") 
        { 
            ddirection = currentRoom->getDirection(commands[1]);
            if (ddirection.getRoomID() != "") 
            {
                id = ddirection.getRoomID();
                currentRoom = gameCastle->getRoom(id);
                myInterface->update();
                
            }
            else {
                myInterface->update("You can not go this direction");
            }
            
        }
        // Make it easier to move, or more user friendly
        else if(commands[0] == "n" || commands[0] == "north" || commands[0] == "s" || commands[0] == "south" || commands[0] == "e" || commands[0] == "east" || commands[0] == "w" || commands[0] == "west") {
            
            if (commands[0].size() > 1) {
                ddirection = currentRoom->getDirection(commands[0]);
            }
            else if (commands[0] == "n") {
                ddirection = currentRoom->getDirection("north");
            }
            else if (commands[0] == "s") {
                ddirection = currentRoom->getDirection("south");
            }
            else if (commands[0] == "w") {
                ddirection = currentRoom->getDirection("west");
            }
            else if (commands[0] == "e") {
                ddirection = currentRoom->getDirection("east");
            }
            
            if (ddirection.getRoomID() != "") 
            {
                id = ddirection.getRoomID();
                currentRoom = gameCastle->getRoom(id);
                myInterface->update();
                
            }
            else {
                myInterface->update("You can not go this direction");
            }
            
        }
        
        //check N,E,W,S, north, east west, south
        else if (  ((commands[0] == "pick" && commands.size() > 1) && commands[1] == "up" ) || commands[0] == "get" || commands[0] == "take" )
        {
            int thing = 0;
            if (commands[0] == "pick" && commands[1] == "up")
            {
                thing = 2; // because pick up is 2 word ==> pick up key ==> key will be in the third index in command[]
            }
            else 
            {
                thing = 1; //get key, take key , take something
            }
            
            int count = 0;
            string des;
            long found;
            int objectID[10];
            string objectType[10];

            if (commands.size() > thing) {
                vector<Listing>const * roomInventory = currentRoom->getManifest();
                
                
                for (int index = 0; index < roomInventory->size(); index++)
                {
                    des = roomInventory->at(index).description;
                    
                    des = Utility::lowerCase(des);
                    
                    found = des.find(Utility::removeGarbage(commands[thing]));
                    
                    //found = des.find("Rusty");
                    if (found != string::npos)
                    {
                        objectID[count] = roomInventory->at(index).objectID;
                        objectType[count] = roomInventory->at(index).objectType;
                        count++;
                    }
                }

            }
            //Listing * checkList;
            
            if (count == 1) {
                
                string response = getObject(objectType[0], objectID[0]);
                
                myInterface->update(response);
                
                
            }
            else if( count < 1 )
            {
                myInterface->update("There is no such object in this room, try again");
            }

        }
        
        // Let user drop something out of his inventory
        else if ( commands[0] == "drop" ) {
            
            vector<Listing>const * playerInventory = currentPlayer->inventory.getManifest();
            
            if (commands.size() == 1) {
                // ***TODO create code for prompt in Interface class
                // *** method should be : void getResponse(std::string interfacePrompt, std::string &response);
                
                dropAll(playerInventory);
                
            }
            else {
                
                int thing = 1;
                if (commands[1] == "all")
                {
                    dropAll(playerInventory);
                }
                
                
                
                string des;
                long found;
                int objectID[10];
                string objectType[10];
                int count = 0;
                for (int index = 0; index < playerInventory->size(); index++)
                {
                    des = playerInventory->at(index).description;
                    
                    des = Utility::lowerCase(des);
                    
                    found = des.find(Utility::removeGarbage(commands[thing]));
                    
                    //found = des.find("Rusty");
                    if (found != string::npos)
                    {
                        objectID[count] = playerInventory->at(index).objectID;
                        objectType[count] = playerInventory->at(index).objectType;
                        count++;
                    }
                    else if( count < 1 )
                    {
                        myInterface->update("There is no such object in your inventory, try again");
                    }
                }
                
                if (count == 1) {
                    
                    string response = dropObject(objectType[0], objectID[0]);
                    
                    myInterface->update(response);
                    
                }

                
            }
        }
        else if ( commands[0] == "show" ) {
            
            if (commands[1] == "inventory") {
                myInterface->showPlayerInventory();
            }
            else {
                
                myInterface->update("What do you want me to show?");
            }
        }
        else if ( commands[0] == "i" || commands[0] == "inv" || commands[0] == "inventory") {
            
            myInterface->showPlayerInventory();
        }
        else if ( commands[0] == "h" || commands[0] == "?" || commands[0] == "help" ) {
            
            vector<std::string> * helpFile;
            
            helpFile = loadHelp();
            
            myInterface->showHelp(loadHelp());
            
        }
        else if ( commands[0] == "q" || commands[0] == "quit" || commands[0] == "exit") {
            
            bool validResponse = false;
            
            string interfacePrompt = "Do you really wish to quit?";
            
            while (!validResponse) {
                
                string response;
                
                myInterface->getResponse(interfacePrompt, response);
                
                if (response == "y" || response == "yes") {
                    
                     
                    if (numberOfQuitRequests < 5) {
                        
                        stringstream msg;
                        
                        string msgPrefix = "Sorry ";
                        
                        string msgPostfix = ", you can never leave Dungeons and Princesses!";
                        
                        msg << msgPrefix << currentPlayer->getDesc() << msgPostfix;

                        myInterface->update(msg.str());
                    }
                    else {
                        
                    }
                    validResponse = true;
                    
                }
                
                else if (response == "n" || response == "no") {
                    
                    // don't drop all
                    
                    validResponse = true;
                    
                    myInterface->update("A wise decision!");
                }
                
                else {
                    
                    interfacePrompt = "Invalid response, please enter y/yes or n/no\n\nDo you really wish quit?";
                    
                }
            }

        }
        else {
            
            myInterface->update("What are you trying to say?");
        }
    }
    else {
        myInterface->update("What did you say???");
    }
}

vector<std::string> * Game::loadHelp() {
    
    std::vector<std::string> * helpFile = new std::vector<std::string>;
    
    helpFile->push_back("------------------Help-----------------");
    helpFile->push_back("[ h ? help ] -> Displays this help file");
    helpFile->push_back("[ Moving ]\n\tYou can move by typing abrivated directions such as [ n s e w ]\n\tTyping full direction names such as [ north south east west ]\n\tor by typing [ move go <direction name> ]");
    helpFile->push_back("[ Manipulating objects ]\n\tYou can pick or drop objects in the game by typing [drop or get <object name>] other variations on this command also work\n\tYou may also empty your inventory by typing [drop all]");
    helpFile->push_back("[ i inventory show <inventory> ] -> Displays your inventory");
    
    return helpFile;
}

string Game::dropObject(std::string objectType, int objectID) {
    
    if (objectType == "Key") {
        
        Key * tmpKey = currentPlayer->inventory.getKey(objectID);
        
        currentRoom->add(tmpKey); 
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You removed the ";
        
        string msgPostfix = ", from your inventory and dropped it in this room";
        
        msg << msgPrefix << tmpKey->getDesc() << msgPostfix;
        
        return msg.str();
    }
    else if (objectType == "Potion") {
        
        Potion *tmpPotion  = currentPlayer->inventory.getPotion(objectID);
        currentRoom->add(tmpPotion);
        
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You removed the ";
        
        string msgPostfix = ", from your inventory and dropped it in this room";
        
        msg << msgPrefix << tmpPotion->getDesc() << msgPostfix;
        
        return msg.str();
        
    }
    
    else if (objectType == "Equipment") {
        
        EquipmentType *tmpEquipment  = currentPlayer->inventory.getEquipmentType(objectID);
        currentRoom->add(tmpEquipment); 
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You removed the ";
        
        string msgPostfix = ", from your inventory and dropped it in this room";
        
        msg << msgPrefix << tmpEquipment->getDesc() << msgPostfix;
        
        return msg.str();
        
    }
    else {
                
        string msg = "ERROR**** Invalid somethign really wierd happend ****";
        
        return msg;
    }

}


void Game::dropAll(vector<Listing>const * playerInventory) {
    
    bool validResponse = false;
    
    string interfacePrompt = "Do you really wish to drop all your inventory?";
    
    while (!validResponse) {
        
        string response;
        
        //myInterface->getResponse(interfacePrompt, response);
        
        if (response == "y" || response == "yes") {
            
            // drop all
            
            long itemsInInventory = playerInventory->size();
            
            for (long i = 0; i < itemsInInventory; i++) {
                
                dropObject(playerInventory->at(0).objectType, playerInventory->at(0).objectID);
            }
            
            validResponse = true;
            
            myInterface->update("As you wish, you dropped all your inventory");
            
        }
        
        else if (response == "n" || response == "no") {
            
            // don't drop all
            
            validResponse = true;
            
            myInterface->update("A wise decision!");
        }
        
        else {
            
            interfacePrompt = "Invalid response, please enter y/yes or n/no\n\nDo you really wish to drop all your inventory?";
            
        }
    }

}

std::string Game::getObject(std::string objectType, int objectID) {
    
    if (objectType == "Key") {
        
        Key * tmpKey = currentRoom->getKey(objectID);
        
        currentPlayer->inventory.add(tmpKey); 
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You picked up the ";
        
        string msgPostfix = ", and placed it in your inventory";
        
        msg << msgPrefix << tmpKey->getDesc() << msgPostfix;
        
        return msg.str();
    }
    else if (objectType == "Potion") {
        
        Potion *tmpPotion  = currentRoom->getPotion(objectID);
        currentPlayer->inventory.add(tmpPotion);
        
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You picked up the ";
        
        string msgPostfix = ", and placed it in your inventory";
        
        msg << msgPrefix << tmpPotion->getDesc() << msgPostfix;
        
        return msg.str();
        
    }
    
    else if (objectType == "Equipment") {
        
        EquipmentType *tmpEquipment  = currentRoom->getEquipmentType(objectID);
        currentPlayer->inventory.add(tmpEquipment); 
        
        // send back the message to the interface that you succesfully picked up the object
        // We are using stringstream here to avoid a possible buffer overflow.
        
        stringstream msg;
        
        string msgPrefix = "You picked up the ";
        
        string msgPostfix = ", and placed it in your inventory";
        
        msg << msgPrefix << tmpEquipment->getDesc() << msgPostfix;
        
        return msg.str();
        
    }
    else {
        
        string msg = "ERROR**** Invalid somethign really wierd happend ****";
        
        return msg;
    }

}
/*
 
 }
 else (command [thing] == "helmet"weapon shield, knife, sword....)
 {
 //group nick ...please give me a list of things player can pick it up
 }
 }
 //if the door is close, player need to open
 //open closet if there is something inside
 //open chest , box ....depend on description of River write
 
 else if (command[0] == "help")
 {
 
 }
 else if ( (command[0] == "pick" && command[1] == "up") || command[0] == "get" || command[0] == "take" )
 {
 /*
 
 
 else if (command[0] == "open") 
 {
 //river please give me a list of things player can open such as : door, chest, box, .... 
 if (command [1] == "door")
 {
 
 }
 else if (command[1] == "chest")
 {}
 else if (command[1] == "box")
 {}
 
 }
 else if (command[0] == "attack" || command[0] == "kill")
 {
 }
 
 */    

